-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Serial (CDC) module for USB Host #10283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the pyserial approach! I'd go 100% into it and match APIs exactly and then call it serial
. That way code will just work in CPython too.
You'll want to conditionalize enabling it so that builds without USB Host don't enable it. That should fix the CI.
@@ -2968,6 +2968,10 @@ msgstr "" | |||
msgid "destination buffer must be an array of type 'H' for bit_depth = 16" | |||
msgstr "" | |||
|
|||
#: shared-bindings/usb/cdc_host/__init__.c | |||
msgid "device must be a usb.core.Device object" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of adding a new message, reuse "%q must be of type %q, not %q"
. (I'd search for where it is used to copy it's example.)
usb/cdc_host/Serial.c \ | ||
usb/cdc_host/__init__.c \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely needs to match the other whitespace.
static const mp_rom_map_elem_t usb_cdc_host_module_globals_table[] = { | ||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_dot_cdc_host) }, | ||
{ MP_ROM_QSTR(MP_QSTR_Serial), MP_ROM_PTR(&usb_cdc_host_serial_type) }, | ||
{ MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&usb_cdc_host_find_obj) }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add a find. Instead, match pyserial exactly with: https://pyserial.readthedocs.io/en/latest/tools.html#serial.tools.list_ports.comports
Thanks for the feedback! I was thinking some more about the tradeoffs between implementing the low level endpoint API vs high level serial API, and I changed my mind and am leaning more towards the EndpointStream for a few reasons:
Curious to hear your thoughts. I can close this and open a new PR. |
It's up to you what you'd like to implement. I'd lean against EndpointStream because it'd be a new unique API. This higher level has the advantage of matching the existing pyserial api. The low level core APIs match pyusb in CPython. Is there a pyusb version of EndpointStream? |
This is a module wrapping TinyUSB's
class/cdc/cdc_host
library into a pyserial-like API so that a CircuitPython board with a USB Host can talk to other devices with CDC interfaces over USB.It is possible to talk CDC using only the
usb.core.Device.read
/.write
methods. However, this only works in blocking mode. I tried setting up asynchronous communication by supplying a timeout to.read()
, but when I tested my code I missed data.As I understand, CDC reads are performed by sending an
IN
packet, then waiting for the device to eventually send aDATA
packet back. This transaction cannot be cancelled halfway through, so even if CircuitPython times out and moves onto other things, the data transfer is going to happen regardless.I think the only way to build an asynchronous API around sending data through the
usb.core
library is to use FIFOs so that even if CircuitPython times out and moves on, the data is still appended to the FIFO and can be read back later. This is how TinyUSB's Endpoint Stream API works. Theclass/cdc/cdc_host
library I am wrapping internally uses Endpoint Streams for the rx and tx endpoints.I was debating building a module around the cdc host or endpoint streams and decided against endpoint streams since they are only exposed in TinyUSB's private headers. They don't require a significant amount of code to implement though, so if you think that it is better to build a lower-level library than a higher-level library I could submit that as a PR instead. I have most of the code written, but it does not work yet.